function Query()
{
	this.doc = null;
	this.docs = null;
	this.logical_selector = null;
	this.default_property = null;
	this.not_on = false;
	this.equal_on = false;
	this.equal_obj = null;
	
	/**
	 * 调用以开始一个新的查询条件的构造，开始前必须调用，否则会出错
	 * 
	 * p 第一个查找字段
	 */
	this.start = function(p)
	{
		this.doc = new Object();
		this.docs = new Array();
		this.logical_selector = null;
		this.default_property = p;
		this.not_on = false;
		this.equal_on = false;
		this.equal_obj = null;
		return this;
	}
	/**
	 * 构造空的查找条件
	 */
	this.create_empty_query = function()
	{
		this.doc = new Object();
		this.docs = new Array();
		this.logical_selector = null;
		this.default_property = p;
		this.not_on = false;
		this.equal_on = false;
		this.equal_obj = null;
		return this;
	}
	/**
	 * 在查询条件填写完毕时调用，不调用可能会造成条件构造错误
	 */
	this.done = function()
	{
		if (this.equal_on)
		{
			this.doc = new Object();
			this.doc[this.default_property] = this.equal_obj;
		}
		else
		{
			var temp = new Object();
			temp[this.default_property] = new Object();
			doccpy(temp[this.default_property], this.doc);
			this.doc = temp;
		}
		
		if (this.logical_selector != null)
		{
			this.docs[this.docs.length] = this.doc;
			this.doc = new Object();
			this.doc[this.logical_selector] = this.docs;
		}
	}
	/**
	 * 测试用函数，用以查看构造出来的条件文档
	 */
	 this.show = function()
	 {
		console.log(this.doc);
		console.log(this.docs);
		//console.log(this);
	 }
	 //----------------------------------Comparison Selector----------------------------------------
	/**
	 * equal，构造“=”条件
	 * 【注】调用eq()方法后，同属性的not(),gt(),gte(),lt(),lte()等比较条件将被忽略
	 * 
	 * o 查找条件
	 */
	this.eq = function(o)
	{
		this.equal_on = true;
		this.equal_obj = o;
		return this;
	}
	/**
	 * greater than，构造“>”条件
	 * 
	 * o 查找条件
	 */
	 this.gt = function(o)
	 {
		if (this.not_on)
		{
			var temp = new Object();
			temp["$gt"] = o;
			this.doc["$not"] = new Object();
			doccpy(this.doc["$not"], temp);
			this.not_on = false;
		}
		else
		{
			this.doc["$gt"] = o;
		}
		return this;
	 }
	/**
	 * equal or greater than，构造“>=”条件
	 * 
	 * o 查找条件
	 */
	this.gte = function(o)
	{
		if (this.not_on)
		{
			var temp = new Object();
			temp["$gte"] = o;
			this.doc["$not"] = new Object();
			doccpy(this.doc["$not"], temp);
			this.not_on = false;
		}
		else
		{
			this.doc["$gte"] = o;
		}
		return this;
	}
	/**
	 * less than，构造“<”条件
	 * 
	 * o 查找条件
	 */
	this.lt = function(o)
	{
		if (this.not_on)
		{
			var temp = new Object();
			temp["$lt"] = o;
			this.doc["$not"] = new Object();
			doccpy(this.doc["$not"], temp);
			this.not_on = false;
		}
		else
		{
			this.doc["$lt"] = o;
		}
		return this;
	}
	/**
	 * equal or less than，构造“<=”条件
	 * 
	 * o 查找条件
	 */
	this.lte = function(o)
	{
		if (this.not_on)
		{
			var temp = new Object();
			temp["$lte"] = o;
			this.doc["$not"] = new Object();
			doccpy(this.doc["$not"], temp);
			this.not_on = false;
		}
		else
		{
			this.doc["$lte"] = o;
		}
		return this;
	}
	/**
	 * 构造“取值落在某一个集合中”的条件
	 * 
	 * o 查找条件
	 */
	this.in_array = function(os)
	{
		if (this.not_on)
		{
			var temp = new Object();
			temp["$in"] = o;
			this.doc["$not"] = new Object();
			doccpy(this.doc["$not"], temp);
			this.not_on = false;
		}
		else
		{
			this.doc["$in"] = o;
		}
		return this;
	}
	/**
	 * not equal，构造“!=”的条件，当该字段不存在时也会被查找到
	 * 
	 * o 查找条件
	 */
	this.ne = function(o)
	{
		if (this.not_on)
		{
			var temp = new Object();
			temp["$ne"] = o;
			this.doc["$not"] = new Object();
			doccpy(this.doc["$not"], temp);
			this.not_on = false;
		}
		else
		{
			this.doc["$ne"] = o;
		}
		return this;
	}
	/**
	 * not in，构造“取值不在某一个集合中”的条件，当该字段不存在时也会被查找到
	 * 
	 * o 查找条件
	 */
	this.nin = function(o)
	{
		if (this.not_on)
		{
			var temp = new Object();
			temp["$nin"] = o;
			this.doc["$not"] = new Object();
			doccpy(this.doc["$not"], temp);
			this.not_on = false;
		}
		else
		{
			this.doc["$nin"] = o;
		}
		return this;
	}
	//--------------------------------Logical Selector---------------------------------------------
	/**
	 * 用And逻辑连接符连接条件
	 * 
	 * p 新的查找字段
	 */
	this.and = function(p)
	{
		if (this.equal_on)
		{
			this.doc = new Object()
			this.doc[this.default_property] = this.equal_obj;
			this.equal_on = false;
		}
		else
		{
			var temp = new Object();
			doccpy(temp, this.doc);
			this.doc = new Object();
			this.doc[this.default_property] = new Object();
			this.doc[this.default_property] = temp;
		}
		this.docs[this.docs.length] = this.doc;
		this.not_on = false;
		this.default_property = p;
		this.doc = new Object();
		
		if (this.logical_selector == null)
		{
			this.logical_selector = "$and";
		}
		else
		{
			if ("$and" != this.logical_selector)
			{
				this.doc[this.logical_selector] = this.docs;
				this.docs = new Array();
				this.docs[this.docs.length] = this.doc;
				this.logical_selector = "$and";
				this.doc = new Object();
			}
		}
		return this;
	}
	/**
	 * 用or逻辑连接符连接条件
	 * 
	 * p 新的查找字段
	 */
	this.or = function(p)
	{
		if (this.equal_on)
		{
			this.doc = new Object()
			this.doc[this.default_property] = this.equal_obj;
			this.equal_on = false;
		}
		else
		{
			var temp = new Object();
			doccpy(temp, this.doc);
			this.doc = new Object();
			this.doc[this.default_property] = new Object();
			this.doc[this.default_property] = temp;
		}
		this.docs[this.docs.length] = this.doc;
		this.not_on = false;
		this.default_property = p;
		this.doc = new Object();
		
		if (this.logical_selector == null)
		{
			this.logical_selector = "$or";
		}
		else
		{
			if ("$or" != this.logical_selector)
			{
				this.doc[this.logical_selector] = this.docs;
				this.docs = new Array();
				this.docs[this.docs.length] = this.doc;
				this.logical_selector = "$or";
				this.doc = new Object();
			}
		}
		return this;
	}
	/**
	 * 为下一个条件添加“not”逻辑选择符，需要说明：如果“not”选择符作用的属性不存在的时候，该条件也为真
	 */
	this.not = function()
	{
		this.not_on = ! this.not_on;
		if (this.not_on)
		{
			if (this.doc["$not"] != undefined)	//"$not" has already been used at least once
			{
				this.and(this.default_property).not();
			}
		}
		return this;
	}
	/**
	 * 用nor逻辑连接符连接条件
	 * 
	 * p 新的查找字段
	 */
	this.nor = function(p)
	{
		if (this.equal_on)
		{
			this.doc = new Object()
			this.doc[this.default_property] = this.equal_obj;
			this.equal_on = false;
		}
		else
		{
			var temp = new Object();
			doccpy(temp, this.doc);
			this.doc = new Object();
			this.doc[this.default_property] = new Object();
			this.doc[this.default_property] = temp;
		}
		this.docs[this.docs.length] = this.doc;
		this.not_on = false;
		this.default_property = p;
		this.doc = new Object();
		
		if (this.logical_selector == null)
		{
			this.logical_selector = "$nor";
		}
		else
		{
			if ("$nor" != this.logical_selector)
			{
				this.doc[this.logical_selector] = this.docs;
				this.docs = new Array();
				this.docs[this.docs.length] = this.doc;
				this.logical_selector = "$nor";
				this.doc = new Object();
			}
		}
		return this;
	}
	//------------------------------------Other Selectors------------------------------------------
	/**
	 * 在当前条件字段下加入正则表达式条件，以及正则表达式选项
	 * 		选项		说明
	 * 		i			切换至大小写不敏感的匹配模式
	 * 		m			切换至多行匹配模式，即匹配字符串中含有换行符（“\n”）或者行开始、结束符时，继续匹配
	 * 		x			空白字符除了被转义的或在字符类中的以外完全被忽略，在未转义的字符类之外的 “#”以及下一个换行符之间的所有字符，包括两头，也都被忽略
	 * 		s			允许点字符（“.”）匹配包括换行符在内的所有字符
	 * 
	 * exp 正则表达式
	 * options 正则表达式的开关选项，null表示不添加选项
	 */
	this.regex = function(exp, opt)
	{
		if (this.not_on)
		{
			var temp = new Object();
			temp["$regex"] = exp;
			if (opt != null)
			{
				temp["$options"] = opt;
			}
			this.doc["$not"] = temp;
			this.not_on = false;
		}
		else
		{
			this.doc["$regex"] = exp;
			if (opt != null)
			{
				this.doc["$options"] = opt;
			}
		}
		return this;
	}
	/**
	 * 构造“has all”的条件，即选择当前字段所对应的数组里包含条件数组内所有元素的文档
	 * 
	 * os 条件数组
	 */
	this.has_all = function(os)
	{
		if (this.not_on)
		{
			var temp = new Object()
			temp["$all"] = os;
			this.doc["$not"] = temp;
			this.not_on = false;
		}
		else
		{
			this.doc["$all"] = os;
		}
		return this;
	}
}

doccpy = function(ndoc, odoc)
{
	for (var i in odoc)
	{
		ndoc[i] = odoc[i];
	}
}
exports.Query = Query;